Skip to content

feat: native multipart upload#3566

Merged
isekovanic merged 29 commits intodevelopfrom
feat/native-multipart-upload
Apr 24, 2026
Merged

feat: native multipart upload#3566
isekovanic merged 29 commits intodevelopfrom
feat/native-multipart-upload

Conversation

@isekovanic
Copy link
Copy Markdown
Contributor

@isekovanic isekovanic commented Apr 23, 2026

🎯 Goal

This PR adds optional native multipart upload support for React Native and Expo packages, with native iOS/Android uploaders, a JS axios adapter, upload progress propagation and new attachment progress UI. Additionally, it also moves pending attachment uploads onto client.uploadManager, adds local attachment id tracking, improves video/document attachment handling, and updates SampleApp to exercise the new native upload path.

The reason why we decided to add an opt-in native upload is related to the fact that axios does not always report upload progress correctly on React Native, especially Android. It will sometimes either not update the progress at all or report it badly, causing UI glitches. Additionally, native uploads are much, much faster as we take advantage of streaming directly without any intermediate ephemeral files in order to do that. Finally, axios can easily break if an override to the underlying RN's fetch implementation has been made, especially on Android.

What Changed

  • Added a shared native multipart upload module for iOS and Android, including request parsing, file/text multipart parts, progress events, cancellation, timeouts, response handling, and bounded response body reads.
  • Added native package and Expo package bindings for StreamMultipartUploader, plus native handler registration through stream-chat-react-native and stream-chat-expo
  • Added core JS helpers and public types for native multipart upload requests, responses, progress events, abort handling, and uploader creation
  • Added installNativeMultipartAdapter / wrapAxiosAdapterWithNativeMultipart to route multipart FormData axios requests through the native uploader when available, while leaving non-multipart requests on the existing adapter
  • Added Chat support for enabling native multipart uploads via useNativeMultipartUpload; SampleApp enables this path
  • Reworked pending message attachment uploads to use client.uploadManager.upload by local attachment id instead of directly calling channel.sendImage / channel.sendFile
  • Added localId propagation from local attachments into message attachments so pending uploads can be correlated with client.uploadManager
  • Updated message sendability and upload indicator behavior to depend on allowSendBeforeAttachmentsUpload rather than offline support
  • Added upload progress UI for image, video, file, and audio attachments, including circular determinate progress, media overlays, file/audio byte progress labels, and a short completion hold to avoid UI flicker
  • Added new overrideable/default components for attachment upload progress: AttachmentUploadIndicator, CircularProgressIndicator, and MediaUploadProgressOverlay
  • Updated gallery/video thumbnail rendering so pending media attachments can show upload progress overlays
  • Updated document picking in both native and Expo packages to generate thumbnails for picked video files (this was missing from V9 initially)
  • Updated iOS video thumbnail URL handling to strip query and fragment data from local file URLs
  • Refined native iOS shimmer behavior to reduce animation restarts, handle foreground/background transitions, visibility, alpha, trait changes, and resolved color updates more reliably (this should improve shimmer performance for iOS significantly)
  • Updated Android shared native source syncing to resolve shared native sources from the canonical project path
  • Replaced SampleApp’s react-native-fast-image dependency with @d11/react-native-fast-image

🛠 Implementation details

🎨 UI Changes

iOS
Before After
Android
Before After

🧪 Testing

☑️ Checklist

  • I have signed the Stream CLA (required)
  • PR targets the develop branch
  • Documentation is updated
  • New code is tested in main example apps, including all possible scenarios
    • SampleApp iOS and Android
    • Expo iOS and Android

@isekovanic isekovanic requested a review from oliverlaz April 24, 2026 12:07
# Conflicts:
#	package/src/components/Attachment/__tests__/Attachment.test.tsx
#	package/src/components/Attachment/__tests__/Giphy.test.tsx
@Stream-SDK-Bot
Copy link
Copy Markdown
Contributor

Stream-SDK-Bot commented Apr 24, 2026

SDK Size

title develop branch diff status
js_bundle_size 353 KB 360 KB +7646 B 🔴

# Conflicts:
#	package/src/components/Attachment/Attachment.tsx
#	package/src/components/Attachment/AttachmentFileUploadProgressIndicator.tsx
#	package/src/components/Attachment/AttachmentUploadIndicator.tsx
#	package/src/components/Attachment/CircularProgressIndicator.tsx
#	package/src/components/Attachment/FileAttachment.tsx
#	package/src/components/Attachment/Gallery.tsx
#	package/src/components/Attachment/VideoThumbnail.tsx
#	package/src/components/Attachment/__tests__/Attachment.test.tsx
#	package/src/components/Attachment/__tests__/Giphy.test.tsx
#	package/src/components/Channel/Channel.tsx
#	package/src/components/index.ts
#	package/src/hooks/usePendingAttachmentUpload.ts
@isekovanic isekovanic merged commit 9a54ed0 into develop Apr 24, 2026
4 of 5 checks passed
@isekovanic isekovanic deleted the feat/native-multipart-upload branch April 24, 2026 12:51
@github-actions github-actions Bot mentioned this pull request Apr 24, 2026
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants